package com.company.genealogy.web.controller;

import com.company.genealogy.common.constant.ApiCodeEnum;
import com.company.genealogy.common.result.ApiResponse;
import com.company.genealogy.common.util.JwtUtil;
import com.company.genealogy.common.util.RedisUtil;
import com.company.genealogy.web.dto.LoginDTO;
import com.company.genealogy.web.dto.LoginResponseDTO;
import com.company.genealogy.web.dto.RefreshTokenDTO;
import com.company.genealogy.web.entity.Role;
import com.company.genealogy.web.entity.User;
import com.company.genealogy.web.service.RoleService;
import com.company.genealogy.web.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 认证控制器
 * 
 * 提供用户登录、登出、token刷新等认证相关功能。
 * 支持JWT token的生成、验证和刷新。
 * 
 * @author chenzhixiang
 */
@RestController
@RequestMapping("/api/v1/auth")
public class AuthController {

    @Autowired
    private UserService userService;

    @Autowired
    private RoleService roleService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private RedisUtil redisUtil;

    /**
     * 用户登录
     * 
     * 验证用户名和密码，生成访问token和刷新token。
     * 
     * @param loginDTO 登录请求参数
     * @return 登录响应信息
     */
    @PostMapping("/login")
    public ApiResponse<LoginResponseDTO> login(@RequestBody LoginDTO loginDTO) {
        // 参数验证
        if (loginDTO.getUsername() == null || loginDTO.getUsername().trim().isEmpty()) {
            return ApiResponse.error(ApiCodeEnum.PARAM_ERROR, "用户名不能为空");
        }
        if (loginDTO.getPassword() == null || loginDTO.getPassword().trim().isEmpty()) {
            return ApiResponse.error(ApiCodeEnum.PARAM_ERROR, "密码不能为空");
        }

        // 查询用户
        User user = userService.getByUsername(loginDTO.getUsername());
        if (user == null) {
            return ApiResponse.error(ApiCodeEnum.LOGIN_ERROR, "用户名或密码错误");
        }

        // 验证用户状态
        if (user.getStatus() != null && user.getStatus() == 0) {
            return ApiResponse.error(ApiCodeEnum.LOGIN_ERROR, "用户已被禁用");
        }

        // 验证密码
        if (!passwordEncoder.matches(loginDTO.getPassword(), user.getPasswordHash())) {
            return ApiResponse.error(ApiCodeEnum.LOGIN_ERROR, "用户名或密码错误");
        }

        // 验证用户类型（只允许admin类型用户登录后台）
        if (!"admin".equals(user.getUserType())) {
            return ApiResponse.error(ApiCodeEnum.LOGIN_ERROR, "该用户类型不允许登录后台管理系统");
        }

        // 获取用户角色和权限
        List<Role> roles = roleService.getRolesByUserId(user.getId());
        String authorities = roles.stream()
                .map(Role::getCode)
                .collect(Collectors.joining(","));

        // 生成token
        String accessToken = jwtUtil.generateAccessToken(
                user.getId(), user.getUsername(), user.getUserType(),
                user.getClanId(), user.getBranchId(), user.getMemberId(), authorities
        );
        String refreshToken = jwtUtil.generateRefreshToken(user.getId(), user.getUsername());

        // 存储token到Redis
        redisUtil.storeAccessToken(user.getId(), accessToken, jwtUtil.getAccessTokenExpiration());
        redisUtil.storeRefreshToken(user.getId(), refreshToken, jwtUtil.getRefreshTokenExpiration());

        // 更新用户最后登录时间
        userService.updateLastLoginTime(user.getId());

        // 构建响应
        LoginResponseDTO response = new LoginResponseDTO();
        response.setAccessToken(accessToken);
        response.setRefreshToken(refreshToken);
        response.setAccessTokenExpiresIn(jwtUtil.getAccessTokenExpiration());
        response.setRefreshTokenExpiresIn(jwtUtil.getRefreshTokenExpiration());
        response.setUserId(user.getId());
        response.setUsername(user.getUsername());
        response.setNickname(user.getNickname());
        response.setAvatar(user.getAvatar());
        response.setUserType(user.getUserType());
        response.setClanId(user.getClanId());
        response.setBranchId(user.getBranchId());
        response.setMemberId(user.getMemberId());
        response.setAuthorities(authorities);

        return ApiResponse.success(ApiCodeEnum.SUCCESS, response);
    }

    /**
     * 刷新token
     * 
     * 使用刷新token获取新的访问token。
     * 
     * @param refreshTokenDTO 刷新token请求参数
     * @return 新的token信息
     */
    @PostMapping("/refresh")
    public ApiResponse<LoginResponseDTO> refreshToken(@RequestBody RefreshTokenDTO refreshTokenDTO) {
        if (refreshTokenDTO.getRefreshToken() == null || refreshTokenDTO.getRefreshToken().trim().isEmpty()) {
            return ApiResponse.error(ApiCodeEnum.PARAM_ERROR, "刷新token不能为空");
        }

        try {
            // 验证刷新token
            if (!jwtUtil.validateToken(refreshTokenDTO.getRefreshToken())) {
                return ApiResponse.error(ApiCodeEnum.TOKEN_ERROR, "刷新token无效或已过期");
            }

            // 从token中获取用户信息
            Long userId = jwtUtil.getUserIdFromToken(refreshTokenDTO.getRefreshToken());
            String username = jwtUtil.getUsernameFromToken(refreshTokenDTO.getRefreshToken());

            // 验证Redis中的刷新token
            String storedRefreshToken = redisUtil.getRefreshToken(userId);
            if (storedRefreshToken == null || !storedRefreshToken.equals(refreshTokenDTO.getRefreshToken())) {
                return ApiResponse.error(ApiCodeEnum.TOKEN_ERROR, "刷新token无效");
            }

            // 获取用户信息
            User user = userService.getById(userId);
            if (user == null) {
                return ApiResponse.error(ApiCodeEnum.TOKEN_ERROR, "用户不存在");
            }

            if (user.getStatus() != null && user.getStatus() == 0) {
                return ApiResponse.error(ApiCodeEnum.LOGIN_ERROR, "用户已被禁用");
            }

            // 获取用户角色和权限
            List<Role> roles = roleService.getRolesByUserId(user.getId());
            String authorities = roles.stream()
                    .map(Role::getCode)
                    .collect(Collectors.joining(","));

            // 生成新的访问token
            String newAccessToken = jwtUtil.generateAccessToken(
                    user.getId(), user.getUsername(), user.getUserType(),
                    user.getClanId(), user.getBranchId(), user.getMemberId(), authorities
            );

            // 更新Redis中的访问token
            redisUtil.storeAccessToken(user.getId(), newAccessToken, jwtUtil.getAccessTokenExpiration());

            // 构建响应
            LoginResponseDTO response = new LoginResponseDTO();
            response.setAccessToken(newAccessToken);
            response.setRefreshToken(refreshTokenDTO.getRefreshToken()); // 返回原刷新token
            response.setAccessTokenExpiresIn(jwtUtil.getAccessTokenExpiration());
            response.setRefreshTokenExpiresIn(jwtUtil.getRefreshTokenExpiration());
            response.setUserId(user.getId());
            response.setUsername(user.getUsername());
            response.setNickname(user.getNickname());
            response.setAvatar(user.getAvatar());
            response.setUserType(user.getUserType());
            response.setClanId(user.getClanId());
            response.setBranchId(user.getBranchId());
            response.setMemberId(user.getMemberId());
            response.setAuthorities(authorities);

            return ApiResponse.success(ApiCodeEnum.SUCCESS, response);

        } catch (Exception e) {
            return ApiResponse.error(ApiCodeEnum.TOKEN_ERROR, "刷新token失败");
        }
    }

    /**
     * 用户登出
     * 
     * 清除用户的token信息。
     * 
     * @return 登出结果
     */
    @PostMapping("/logout")
    public ApiResponse<Void> logout() {
        // 从请求头中获取token（这里需要从SecurityContext中获取用户信息）
        // 实际实现中，用户ID应该从SecurityContext中获取
        // 这里简化处理，实际使用时需要从JWT中解析用户ID
        
        return ApiResponse.success(ApiCodeEnum.SUCCESS, null);
    }

    /**
     * 强制登出用户
     * 
     * 管理员可以强制登出指定用户。
     * 
     * @param userId 用户ID
     * @return 登出结果
     */
    @PostMapping("/logout/{userId}")
    public ApiResponse<Void> forceLogout(@PathVariable Long userId) {
        // 清除用户的所有token
        redisUtil.deleteAllTokens(userId);
        
        // 将用户加入黑名单（可选）
        // redisUtil.addToBlacklist(userId, jwtUtil.getAccessTokenExpiration());
        
        return ApiResponse.success(ApiCodeEnum.SUCCESS, null);
    }
} 